home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 2 / ETO Development Tools 2.iso / Tools - Objects / MacApp / MacApp CD Release / MacApp 2.0.1 (Many Libraries) / Libraries / UTEView.TTECommand.p < prev    next >
Encoding:
Text File  |  1990-10-25  |  30.9 KB  |  1,107 lines  |  [TEXT/MPS ]

  1. {$P}
  2. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  3. {UTEView.TTECommand.p}
  4. {Copyright © 1984-1990 Apple Computer Inc. All rights reserved.}
  5.  
  6. {--------------------------------------------------------------------------------------------------}
  7. {$S TESelCommand}
  8.  
  9. PROCEDURE TTECommand.ITECommand(itsTEView: TTEView;
  10.                                 itsCmdNumber: CmdNumber;
  11.                                 itsSaveText: BOOLEAN);
  12.  
  13.     VAR
  14.         selChars:            INTEGER;
  15.         h:                    Handle;
  16.         fi:                 FailInfo;
  17.  
  18.     PROCEDURE HdlInitFailed(error: OSErr;
  19.                             message: LONGINT);
  20.  
  21.         BEGIN
  22.         Free;
  23.         END;
  24.  
  25.     BEGIN
  26.     fTEView := itsTEView;
  27.     fHTE := itsTEView.fHTE;
  28.  
  29.     WITH fHTE^^ DO
  30.         BEGIN
  31.         fOldStart := selStart;
  32.         fOldEnd := selEnd;
  33.         selChars := selEnd - selStart;
  34.         END;
  35.  
  36.     fOldText := NIL;
  37.     fOldStyles := NIL;
  38.  
  39.     fNewStart := 0;
  40.     fNewEnd := 0;
  41.     fNewText := NIL;
  42.     fNewStyles := NIL;
  43.  
  44.     fPadding := NIL;
  45.     fTextPad := 0;
  46.     fStylePad := 0;
  47.  
  48.     ICommand(itsCmdNumber, itsTEView.fDocument, itsTEView, NIL);
  49.     CatchFailures(fi, HdlInitFailed);
  50.  
  51.     IF itsSaveText THEN
  52.         BEGIN
  53.         h := NewPermHandle(selChars);
  54.         FailNIL(h);
  55.  
  56.         IF selChars > 0 THEN
  57.             BlockMove(Pointer(ORD(fHTE^^.hText^) + fOldStart), h^, selChars);
  58.  
  59.         fOldText := h;
  60.         fTextPad := fOldStart - fOldEnd;
  61.         fPadding := NewPermHandle(0);
  62.         FailNIL(fPadding);
  63.         END;
  64.  
  65.  { TextEdit has this "feature" which it exercises if it runs out of memory.  It's
  66.    called DS number 25.  We'll try to avoid it by assuring that enough memory exists
  67.    to fulfill the request, but we won't die because of it.  This is a particularly
  68.    ugly situation - there could be >600K of style information associated with a 32K
  69.    block of text.  And to support undo, we've got to assume that there may momentarily
  70.    be THREE copies floating around, adding up to a total potential liability of almost
  71.    2 Meg for a single TE record.  The worst that can happen, though, is that the text
  72.    will be safe, but it won't have any styles associated with it. }
  73.  
  74.     IF (itsTEView.fStyleType = kWithStyle) & itsTEView.SpaceForStyles(fHTE^^.selStart,
  75.                                                                       fHTE^^.selEnd) THEN
  76.         BEGIN
  77.         fOldStyles := GetStylScrap(fHTE);
  78.         FailNIL(fOldStyles);
  79.         fStylePad := GetHandleSize(Handle(fOldStyles));
  80.         END;
  81.  
  82.     Success(fi);
  83.  
  84.     END;
  85.  
  86. {--------------------------------------------------------------------------------------------------}
  87. {$S TEDoCommand}
  88.  
  89. PROCEDURE TTECommand.Free; OVERRIDE;
  90.  
  91.     BEGIN
  92.     fOldText := DisposeIfHandle(fOldText);
  93.     Handle(fOldStyles) := DisposeIfHandle(fOldStyles);
  94.     fNewText := DisposeIfHandle(fNewText);
  95.     Handle(fNewStyles) := DisposeIfHandle(fNewStyles);
  96.     fPadding := DisposeIfHandle(fPadding);
  97.  
  98.     INHERITED Free;
  99.     END;
  100.  
  101. {--------------------------------------------------------------------------------------------------}
  102. {$S TEDoCommand}
  103.  
  104. PROCEDURE TTECommand.BanishOldText;
  105.  
  106.     BEGIN
  107.     IF fOldEnd > fOldStart THEN
  108.         TEDelete(fHTE);
  109.     SetHandleSize(fPadding, MAX( - (fTextPad + fStylePad), 0));
  110.     FailMemError;
  111.     END;
  112.  
  113. {--------------------------------------------------------------------------------------------------}
  114. {$S TEDoCommand}
  115.  
  116. PROCEDURE TTECommand.InstallNewText;
  117.  
  118.     VAR
  119.         savedSize:            LONGINT;
  120.         itsText:            Handle;
  121.  
  122.     BEGIN
  123.     IF fNewEnd > fNewStart THEN
  124.         BEGIN
  125.         itsText := fTEView.fText;
  126.         savedSize := GetHandleSize(itsText);
  127.  
  128.         {$IFC qDebug}
  129.         IF fNewText = NIL THEN
  130.             ProgramBreak('InstallNewText called with fNewText = NIL!');
  131.         {$ENDC}
  132.  
  133.         LockHandleHigh(fNewText);                                { Prevent heap fragmentation for TEInsert }
  134.  
  135.         IF fTEView.fStyleType = kWithStyle THEN         { If record has style, use it }
  136.             TEStylInsert(fNewText^,                     { It's okay for fNewStyles to be NIL here }
  137.                          GetHandleSize(fNewText), fNewStyles, fHTE)
  138.         ELSE                                            { Otherwise, do it the old-fashioned way }
  139.             TEInsert(fNewText^, GetHandleSize(fNewText), fHTE);
  140.  
  141.         HUnlock(fNewText);
  142.  
  143.         IF GetHandleSize(itsText) <= savedSize THEN
  144.             FailOSErr(memFullErr);
  145.  
  146.         fTEView.fSpecsChanged := TRUE;
  147.         END;
  148.     END;
  149.  
  150. {--------------------------------------------------------------------------------------------------}
  151. {$S TEFields}
  152.  
  153. PROCEDURE TTECommand.Fields(PROCEDURE DoToField(fieldName: Str255;
  154.                                                 fieldAddr: Ptr;
  155.                                                 fieldType: INTEGER)); OVERRIDE;
  156.  
  157.     BEGIN
  158.     DoToField('TTECommand', NIL, bClass);
  159.     DoToField('fTEView', @fTEView, bObject);
  160.     DoToField('fHTE', @fHTE, bTEHandle);
  161.     DoToField('fOldStart', @fOldStart, bInteger);
  162.     DoToField('fOldEnd', @fOldEnd, bInteger);
  163.     DoToField('fOldText', @fOldText, bHandle);
  164.     DoToField('fOldStyles', @fOldStyles, bHandle);
  165.     DoToField('fNewStart', @fNewStart, bInteger);
  166.     DoToField('fNewEnd', @fNewEnd, bInteger);
  167.     DoToField('fNewText', @fNewText, bHandle);
  168.     DoToField('fNewStyles', @fNewStyles, bHandle);
  169.     DoToField('fPadding', @fPadding, bHandle);
  170.     DoToField('fTextPad', @fTextPad, bInteger);
  171.     DoToField('fStylePad', @fStylePad, bLongInt);
  172.     INHERITED Fields(DoToField);
  173.     END;
  174.  
  175. {--------------------------------------------------------------------------------------------------}
  176. {$S TEDoCommand}
  177.  
  178. PROCEDURE TTECommand.RemoveAdditions;
  179.  
  180.     BEGIN
  181.     IF fNewText <> NIL THEN
  182.         BEGIN
  183.         TESetSelect(fNewStart, fNewEnd, fHTE);
  184.         TEDelete(fHTE);
  185.         END;
  186.     SetHandleSize(fPadding, MAX(fTextPad + fStylePad, 0));
  187.     FailMemError;
  188.     END;
  189.  
  190. {--------------------------------------------------------------------------------------------------}
  191. {$S TEDoCommand}
  192.  
  193. PROCEDURE TTECommand.RestoreSelection;
  194.  
  195.     BEGIN
  196.     TESetSelect(fOldStart, fOldEnd, fHTE);
  197.     END;
  198.  
  199. {--------------------------------------------------------------------------------------------------}
  200. {$S TEDoCommand}
  201.  
  202. PROCEDURE TTECommand.ReviveDeletions;
  203.  
  204.     VAR
  205.         itsText:            Handle;
  206.         savedSize:            LONGINT;
  207.         nChars:             INTEGER;
  208.  
  209.     BEGIN
  210.     TESetSelect(fOldStart, fOldStart, fHTE);            { so insert will take place at right point }
  211.     nChars := GetHandleSize(fOldText);
  212.     IF nChars > 0 THEN
  213.         BEGIN
  214.         itsText := fTEView.fText;
  215.         savedSize := GetHandleSize(itsText);
  216.  
  217.         LockHandleHigh(fOldText);                                { Prevent heap fragmentation }
  218.  
  219.         IF fTEView.fStyleType = kWithStyle THEN         { If record has style, use it }
  220.             TEStylInsert(fOldText^, nChars,             { It's okay for fOldStyles to be NIL here }
  221.                          fOldStyles, fHTE)
  222.         ELSE                                            { Otherwise, do it the old-fashioned way }
  223.             TEInsert(fOldText^, nChars, fHTE);
  224.  
  225.         HUnlock(fOldText);
  226.  
  227.         IF GetHandleSize(itsText) <= savedSize THEN
  228.             FailOSErr(memFullErr);
  229.  
  230.         fTEView.fSpecsChanged := TRUE;
  231.         END;
  232.     END;
  233.  
  234. {--------------------------------------------------------------------------------------------------}
  235. {$S TEDoCommand}
  236.  
  237. PROCEDURE TTECommand.DoMainFunction;
  238.  
  239.     BEGIN
  240.     IF fCmdNumber <> cCopy THEN
  241.         BanishOldText;
  242.     InstallNewText;
  243.     IF fCmdNumber <> cCopy THEN
  244.         fTEView.SynchView(kRedraw);
  245.     END;
  246.  
  247. {--------------------------------------------------------------------------------------------------}
  248. {$S TEDoCommand}
  249.  
  250. PROCEDURE TTECommand.DoIt; OVERRIDE;
  251.  
  252.     BEGIN
  253.     IF fTEView.Focus THEN;                                {??? What if Focus fails}
  254.  
  255.     DoMainFunction;
  256.     {$IFC qDebug}
  257.     IF pTEIntenseDebugging THEN
  258.         DumpTTECommand(SELF);
  259.     {$ENDC}
  260.     END;
  261.  
  262. {--------------------------------------------------------------------------------------------------}
  263. {$S TEDoCommand}
  264.  
  265. PROCEDURE TTECommand.UndoIt; OVERRIDE;
  266.  
  267.     BEGIN
  268.     IF fTEView.Focus THEN;                                {??? What if Focus fails}
  269.  
  270.     RemoveAdditions;
  271.     ReviveDeletions;
  272.     RestoreSelection;
  273.     IF fCmdNumber <> cCopy THEN
  274.         fTEView.SynchView(kRedraw);
  275.     {$IFC qDebug}
  276.     IF pTEIntenseDebugging THEN
  277.         DumpTTECommand(SELF);
  278.     {$ENDC}
  279.     END;
  280.  
  281. {--------------------------------------------------------------------------------------------------}
  282. {$S TEDoCommand}
  283.  
  284. PROCEDURE TTECommand.RedoIt; OVERRIDE;
  285.  
  286.     BEGIN
  287.     IF fTEView.Focus THEN;                                {??? What if Focus fails}
  288.  
  289.     RestoreSelection;
  290.     DoMainFunction;
  291.     {$IFC qDebug}
  292.     IF pTEIntenseDebugging THEN
  293.         DumpTTECommand(SELF);
  294.     {$ENDC}
  295.     END;
  296.  
  297. {--------------------------------------------------------------------------------------------------}
  298. {$S TESelCommand}
  299.  
  300. PROCEDURE TTECutCopyCommand.ITECutCopyCommand(itsTEView: TTEView;
  301.                                               itsCmdNumber: CmdNumber);
  302.  
  303.     BEGIN
  304.     fClipCreated := FALSE;
  305.     ITECommand(itsTEView, itsCmdNumber, TRUE);
  306.     fChangesClipboard := TRUE;
  307.     fCausesChange := itsCmdNumber <> cCopy;
  308.     END;
  309.  
  310. {--------------------------------------------------------------------------------------------------}
  311. {$S TEDoCommand}
  312.  
  313. PROCEDURE TTECutCopyCommand.Free; OVERRIDE;
  314.  
  315.     BEGIN
  316.     IF fClipCreated THEN
  317.         fOldText := NIL;
  318.     INHERITED Free;
  319.     END;
  320.  
  321. {--------------------------------------------------------------------------------------------------}
  322. {$S TEDoCommand}
  323.  
  324. PROCEDURE TTECutCopyCommand.DoIt; OVERRIDE;
  325.  
  326.     VAR
  327.         clipTEView:         TTEView;
  328.         clipHere:            BOOLEAN;
  329.         fi:                 FailInfo;
  330.         clipStyle:            TextStyle;
  331.         itsSize:            VPoint;
  332.         itsMargins:         Rect;
  333.  
  334.     PROCEDURE HdlClipFailed(error: OSErr;
  335.                             message: LONGINT);
  336.  
  337.         BEGIN
  338.         FreeIfObject(clipTEView);
  339.         clipTEView := NIL;
  340.         END;
  341.  
  342.     BEGIN                                                {TTECutCopyCommand.DoIt}
  343.     IF fTEView.Focus THEN;                                {??? What if Focus fails}
  344.  
  345.     SetTextStyle(clipStyle, applFont, [],                { Initial style same as virgin TEView }
  346.                  12, gRGBBlack);
  347.  
  348.     SetVPt(itsSize, 100, 50);                            { An arbitrary initial size. }
  349.     SetRect(itsMargins, 10, 8, 10, 0);                    { No bottom margin. }
  350.  
  351.     New(clipTEView);                                    { Create a new view for the clipboard }
  352.     FailNIL(clipTEView);
  353.     WITH fTEView DO
  354.         clipTEView.ITEView(NIL, NIL,                    { Initialize view }
  355.                            gZeroVPt, itsSize, sizeSuperView, sizeVariable, itsMargins, clipStyle,
  356.                            teJustSystem, fStyleType, fAutoWrap);
  357.     clipTEView.fAcceptsChanges := FALSE;                { This is a read-only view }
  358.  
  359.     CatchFailures(fi, HdlClipFailed);                    { Cut can eat into temp memory so users can
  360.                                                          }
  361.     { …rescue text from overweight documents }
  362.     IF NOT fCausesChange THEN                            { If Copy-ing, assure there's enough room }
  363.         FailSpaceIsLow;
  364.     Success(fi);
  365.     clipTEView.StuffText(fOldText);
  366.     FailSpaceIsLow;
  367.  
  368.     {??? GOT TO FIGURE OUT SOME WAY TO PRE-FLIGHT THIS! ??????????????????????????????????? }
  369.     IF clipTEView.fStyleType = kWithStyle THEN            { If record has style }
  370.         SetStylScrap(0, MAXINT, fOldStyles,             { …then put in the styles }
  371.                      kDontRedraw, clipTEView.fHTE);
  372.     FailSpaceIsLow;
  373.  
  374.     clipTEView.fFreeText := TRUE;                        { Let TEView know it has to free the text }
  375.  
  376.     gApplication.ClaimClipboard(clipTEView);            { Okay to claim (will call RecalcText!) }
  377.  
  378.     fClipCreated := TRUE;                                { We be done }
  379.     DoMainFunction;                                     { Do the actual cut/copy }
  380.  
  381.     {$IFC qDebug}
  382.     IF pTEIntenseDebugging THEN
  383.         BEGIN
  384.         DumpTERecord(clipTEView.fHTE);
  385.         DumpTTECommand(SELF);
  386.         END;
  387.     {$ENDC}
  388.     END;
  389.  
  390. {--------------------------------------------------------------------------------------------------}
  391. {$S TEDoCommand}
  392.  
  393. PROCEDURE TTECutCopyCommand.ReviveDeletions; OVERRIDE;
  394.  
  395.     BEGIN
  396.     IF fCmdNumber = cCut THEN
  397.         INHERITED ReviveDeletions;                        { Don't do it for COPY }
  398.     END;
  399.  
  400. {--------------------------------------------------------------------------------------------------}
  401. {$S TEFields}
  402.  
  403. PROCEDURE TTECutCopyCommand.Fields(PROCEDURE DoToField(fieldName: Str255;
  404.                                                        fieldAddr: Ptr;
  405.                                                        fieldType: INTEGER)); OVERRIDE;
  406.  
  407.     BEGIN
  408.     DoToField('TTECutCopyCommand', NIL, bClass);
  409.     DoToField('fClipCreated', @fClipCreated, bBoolean);
  410.     INHERITED Fields(DoToField);
  411.     END;
  412.  
  413. {--------------------------------------------------------------------------------------------------}
  414. {$S TESelCommand}
  415.  
  416. PROCEDURE TTEPasteCommand.ITEPasteCommand(itsTEView: TTEView);
  417. { We can't use TEPaste because it clobbers the DeskScrap; the text would be recoverable
  418.   from the special TextEdit Scrap, but other types of non-TEXT scrap are permanently
  419.   lost, it seems }
  420.  
  421.     VAR
  422.         savedPerm:            BOOLEAN;
  423.         newLength:            INTEGER;
  424.         newStyleLen:        LONGINT;
  425.         newText:            Handle;
  426.         newStyles:            StScrpHandle;
  427.         dataType:            ResType;
  428.         fi:                 FailInfo;
  429.  
  430.     PROCEDURE HdlPasteFailed(error: OSErr;
  431.                              message: LONGINT);
  432.  
  433.         BEGIN
  434.         IF newText <> fNewText THEN                     { newText is assigned to fNewText }
  435.             newText := DisposeIfHandle(newText);        { …so avoid disposing twice. }
  436.         IF newStyles <> fNewStyles THEN                 { Ditto for newStyles. }
  437.             Handle(newStyles) := DisposeIfHandle(newStyles);
  438.         Free;
  439.         END;
  440.  
  441.     BEGIN
  442.     ITECommand(itsTEView, cPaste, TRUE);                { Perform stock initializations }
  443.  
  444.     savedPerm := FALSE;
  445.  
  446.     newStyleLen := 0;                                    { Assume there are no new styles }
  447.     newStyles := NIL;
  448.     newText := NIL;
  449.  
  450.     CatchFailures(fi, HdlPasteFailed);
  451.  
  452.     newText := NewPermHandle(0);                        { Create handle to receive clipboard data }
  453.     FailNIL(newText);
  454.     IF itsTEView.fStyleType = kWithStyle THEN
  455.         BEGIN
  456.         newStyles := StScrpHandle(NewPermHandle(0));    { Same for handle to receive style info }
  457.         FailNIL(newStyles);
  458.         END;
  459.  
  460.     newLength := gApplication.GetDataToPaste(newText, dataType);
  461.  
  462.     IF newLength > 0 THEN
  463.         BEGIN
  464.         {$IFC qDebug}
  465.         IF dataType <> 'TEXT' THEN
  466.             ProgramBreak('TEPasteCommand given some non-text from clipboard')
  467.         ELSE
  468.         {$ENDC}
  469.             BEGIN                                        { Prime "new" values }
  470.             fNewText := newText;
  471.             fNewStart := fHTE^^.selStart;
  472.             fNewEnd := fNewStart + newLength;
  473.             fTextPad := newLength - (fOldEnd - fOldStart);
  474.  
  475.             IF itsTEView.fStyleType = kWithStyle THEN
  476.                 BEGIN
  477.                 newStyleLen := gClipView.GivePasteData(Handle(newStyles), 'styl');
  478.                 IF newStyleLen > 0 THEN
  479.                     BEGIN
  480.                     fNewStyles := newStyles;
  481.                     { Difference between old and new styles }
  482.                     fStylePad := newStyleLen - fStylePad;
  483.                     END
  484.                 ELSE
  485.                     newStyles := StScrpHandle(DisposeIfHandle(newStyles));
  486.                 END;
  487.  
  488.             SetPermHandleSize(fPadding, MAX(fTextPad + fStylePad, 0));
  489.  
  490.             FailSpaceIsLow;
  491.             END;
  492.         END
  493.     ELSE
  494.         BEGIN
  495.         newText := DisposeIfHandle(newText);
  496.         Handle(newStyles) := DisposeIfHandle(newStyles);
  497.         END;
  498.     Success(fi);
  499.     END;
  500.  
  501. {--------------------------------------------------------------------------------------------------}
  502. {$S TEFields}
  503.  
  504. PROCEDURE TTEPasteCommand.Fields(PROCEDURE DoToField(fieldName: Str255;
  505.                                                      fieldAddr: Ptr;
  506.                                                      fieldType: INTEGER)); OVERRIDE;
  507.  
  508.     BEGIN
  509.     DoToField('TTEPasteCommand', NIL, bClass);
  510.     INHERITED Fields(DoToField);
  511.     END;
  512.  
  513. {--------------------------------------------------------------------------------------------------}
  514. {$S TESelCommand}
  515.  
  516. PROCEDURE TTEStyleCommand.ITEStyleCommand(itsTEView: TTEView;
  517.                                           itsNewStyle: TextStyle;
  518.                                           itsCmdNumber: CmdNumber;
  519.                                           itsMode: INTEGER);
  520.  
  521.     VAR
  522.         savedPerm:            BOOLEAN;
  523.         fi:                 FailInfo;
  524.  
  525.     BEGIN
  526.  
  527.     ITECommand(itsTEView, itsCmdNumber, FALSE);         { Perform stock initialization, sans text }
  528.  
  529.     fOldTextStyle := itsTEView.fTextStyle;
  530.     fNewTextStyle := itsNewStyle;
  531.  
  532.     { Only do color change if we can }
  533.     IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  534.         fMode := itsMode
  535.     ELSE
  536.         fMode := BAND(itsMode, BNOT(doColor));
  537.     END;
  538.  
  539. {--------------------------------------------------------------------------------------------------}
  540. {$S TEDoCommand}
  541.  
  542. PROCEDURE TTEStyleCommand.InstallOneStyle(newStyl: TextStyle);
  543.  
  544.     BEGIN
  545.     fTEView.SetOneStyle(fOldStart, fOldEnd, fMode, newStyl, kRedraw); { Focus'es for us }
  546.     END;
  547.  
  548. {--------------------------------------------------------------------------------------------------}
  549. {$S TEDoCommand}
  550.  
  551. PROCEDURE TTEStyleCommand.InstallManyStyles(newStyls: StScrpHandle);
  552.  
  553.     BEGIN
  554.     IF fTEView.Focus THEN;
  555.     { No need to check for fStyleType, since we only get here if the record is stylish }
  556.     SetStylScrap(fOldStart, fOldEnd, newStyls, kRedraw, fHTE);
  557.     fTEView.RecalcText;                                 { Might have changed number of lines }
  558.     fTEView.SynchView(kRedraw);                         { Show corrected view }
  559.  
  560.     fTEView.fSpecsChanged := TRUE;
  561.     END;
  562.  
  563. {--------------------------------------------------------------------------------------------------}
  564. {$S TEDoCommand}
  565.  
  566. PROCEDURE TTEStyleCommand.DoIt; OVERRIDE;
  567.  
  568.     VAR
  569.         aTextStyle:         TextStyle;
  570.  
  571.     BEGIN
  572.     aTextStyle := fNewTextStyle;
  573.     InstallOneStyle(aTextStyle);
  574.     fMode := BAND(fMode, BNOT(doToggle));                { Turn off toggle mode, if set }
  575.     {$IFC qDebug}
  576.     IF pTEIntenseDebugging THEN
  577.         DumpTTECommand(SELF);
  578.     {$ENDC}
  579.     END;
  580.  
  581. {--------------------------------------------------------------------------------------------------}
  582. {$S TEDoCommand}
  583.  
  584. PROCEDURE TTEStyleCommand.UndoIt; OVERRIDE;
  585.  
  586.     VAR
  587.         aTextStyle:         TextStyle;
  588.  
  589.     BEGIN
  590.     RestoreSelection;
  591.  
  592.     IF fTEView.fStyleType = kWithoutStyle THEN
  593.         BEGIN
  594.         aTextStyle := fOldTextStyle;
  595.         InstallOneStyle(aTextStyle);
  596.         END
  597.     ELSE
  598.         InstallManyStyles(fOldStyles);
  599.     {$IFC qDebug}
  600.     IF pTEIntenseDebugging THEN
  601.         DumpTTECommand(SELF);
  602.     {$ENDC}
  603.     END;
  604.  
  605. {--------------------------------------------------------------------------------------------------}
  606. {$S TEDoCommand}
  607.  
  608. PROCEDURE TTEStyleCommand.RedoIt; OVERRIDE;
  609.  
  610.     BEGIN
  611.     RestoreSelection;
  612.     DoIt;
  613.     END;
  614.  
  615. {--------------------------------------------------------------------------------------------------}
  616. {$S TEFields}
  617.  
  618. PROCEDURE TTEStyleCommand.Fields(PROCEDURE DoToField(fieldName: Str255;
  619.                                                      fieldAddr: Ptr;
  620.                                                      fieldType: INTEGER)); OVERRIDE;
  621.  
  622.     BEGIN
  623.     DoToField('TTEStyleCommand', NIL, bClass);
  624.     DoToField('fMode', @fMode, bInteger);
  625.     {$Push} {$H-}
  626.     TextStyleFields('fOldTextStyle', fOldTextStyle, DoToField);
  627.     TextStyleFields('fNewTextStyle', fNewTextStyle, DoToField);
  628.     {$Pop}
  629.     INHERITED Fields(DoToField);
  630.     END;
  631.  
  632. {--------------------------------------------------------------------------------------------------}
  633. {$S TERes}
  634.  
  635. PROCEDURE TTETypingCommand.ITETypingCommand(itsTEView: TTEView;
  636.                                             itsFirstChar: Char);
  637.  
  638.     VAR
  639.         fi:                 FailInfo;
  640.  
  641.     PROCEDURE HdlInitFailed(error: OSErr;
  642.                             message: LONGINT);
  643.  
  644.         BEGIN
  645.         Free;
  646.         END;
  647.  
  648.     BEGIN
  649.     ITECommand(itsTEView, cTyping, TRUE);
  650.  
  651.     CatchFailures(fi, HdlInitFailed);
  652.  
  653.     fNewStart := fHTE^^.selStart;                        { Start and end are the same }
  654.     fNewEnd := fNewStart;
  655.  
  656.     fNewText := NewPermHandle(0);                        { Allocate an empty block for text }
  657.     FailNIL(fNewText);
  658.  
  659.     fCompleted := FALSE;                                { We've only just begun… }
  660.     fFirstChar := itsFirstChar;                         { Save character for Doit }
  661.     Success(fi);
  662.     END;
  663.  
  664. {--------------------------------------------------------------------------------------------------}
  665. {$S TERes}
  666.  
  667. PROCEDURE TTETypingCommand.Free; OVERRIDE;
  668.  
  669.     BEGIN
  670.     IF fTEView.fTypingCommand = SELF THEN
  671.         fTEView.fTypingCommand := NIL;
  672.     INHERITED Free;
  673.     END;
  674.  
  675. {--------------------------------------------------------------------------------------------------}
  676. {$S TERes}
  677.  
  678. PROCEDURE TTETypingCommand.DoNormalChar(aChar: Char);
  679.  
  680.     BEGIN
  681.     FailOSErr(PtrAndHand(Ptr(SUCC(ORD(@aChar))),        { Append char to end of fNewText }
  682.                          fNewText, 1));
  683.     fNewEnd := SUCC(fNewEnd);                            { Bump both end of "selection" }
  684.     fTextPad := SUCC(fTextPad);                         { …and padding value }
  685.  
  686.     SetHandleSize(fPadding,                             { This SetHandleSize can't grow the handle,
  687.                                                          }
  688.                   MAX( - (fTextPad + fStylePad), 0));    { …so it shouldn't fail. }
  689.     FailMemError;
  690.     END;
  691.  
  692. {--------------------------------------------------------------------------------------------------}
  693. { User has backspaced to the left of the original starting point.  First, copy the
  694.  character (which may be more than one byte long if we are using a non-Roman script)
  695.  to a temporary buffer.  The assumption is that no character will ever be longer
  696.  than four bytes.  Sorry, folks, MacApp does not support typing in any script with
  697.  more than 4 billion characters.
  698.   Next, copy the character to the front of fOldText, and adjust fOldStart, fNewStart,
  699.  and fNewEnd.  Note that we do NOT check for MemSpaceIsLow, since we want to let the
  700.  user delete characters. }
  701. {$S TERes}
  702.  
  703. PROCEDURE TTETypingCommand.BkSpcLeft(theText: Handle;
  704.                                      curStart: INTEGER);
  705.  
  706.     TYPE
  707.         TSPtr                = ^TextStyle;
  708.  
  709.     VAR
  710.         savedSize:            INTEGER;
  711.         theHeight:            INTEGER;
  712.         theAscent:            INTEGER;
  713.         oldSize:            LONGINT;
  714.         whoCares:            LONGINT;
  715.         aTextStyle:         TSPtr;
  716.         savedChar:            PACKED ARRAY [0..3] OF Char;
  717.         delStyle:            TextStyle;
  718.         {$IFC qDebug}
  719.         savedPerm:            BOOLEAN;
  720.         {$ENDC}
  721.  
  722.     BEGIN
  723.     savedSize := 1;
  724.     IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
  725.         WHILE CharByte(theText^, curStart - savedSize) > 0 DO
  726.             savedSize := SUCC(savedSize);
  727.     curStart := curStart - savedSize;
  728.  
  729.     {$IFC qDebug}
  730.     IF savedSize > 4 THEN
  731.         ProgramBreak('Character > 4 bytes');
  732.     {$ENDC}
  733.     IF savedSize = 1 THEN                                { Slight speed optimization for normal case
  734.                                                          }
  735.     {$Push} {$R-}
  736.         savedChar[0] := CharsHandle(theText)^^[curStart]
  737.         {$Pop}
  738.     ELSE
  739.         BlockMove(Ptr(ORD(theText^) + curStart), @savedChar, savedSize);
  740.  
  741.     IF fTEView.fStyleType = kWithStyle THEN             { Only do this if styles are around }
  742.         BEGIN
  743.         TEGetStyle(curStart, delStyle,                    { Get the style of the deleted character }
  744.                    theHeight, theAscent, fHTE);         { (1 or 4 bytes, it's all only one style) }
  745.  
  746.         IF NOT EqualBlocks(@delStyle,                    { If style doesn't match first in the list }
  747.                            @fOldStyles^^.scrpStyleTab[0].scrpFont, SIZEOF(TextStyle)) THEN
  748.             BEGIN                                        { …then insert new style at head of list }
  749.             fTEView.fSpecsChanged := TRUE;                { User backspaced into new style! }
  750.  
  751.             oldSize :=                                    { Make room for the new style element }
  752.               GetHandleSize(Handle(fOldStyles));
  753.             SetHandleSize(Handle(fOldStyles), oldSize + SIZEOF(ScrpSTElement));
  754.             FailMemError;
  755.             fStylePad := fStylePad + SIZEOF(ScrpSTElement);
  756.  
  757.             {$Push} {$H-}
  758.             WITH fOldStyles^^.scrpStyleTab[0] DO
  759.                 BlockMove(@scrpStartChar,                { Move entire array up one element's size }
  760.                           Ptr(ORD(@scrpStartChar) + SIZEOF(ScrpSTElement)), oldSize -
  761.                           SIZEOF(fOldStyles^^.scrpNStyles));
  762.             {$Pop}
  763.  
  764.             fOldStyles^^.scrpNStyles :=                 { One more style }
  765.               SUCC(fOldStyles^^.scrpNStyles);
  766.             WITH fOldStyles^^.scrpStyleTab[0] DO
  767.                 BEGIN
  768.                 scrpHeight := theHeight;                { Fill in the blanks }
  769.                 scrpAscent := theAscent;
  770.                 aTextStyle := TSPtr(@scrpFont);
  771.                 aTextStyle^ := delStyle;
  772.                 END;
  773.             END;
  774.  
  775.         WITH fOldStyles^^.scrpStyleTab[0] DO
  776.             scrpStartChar := PRED(scrpStartChar);        { Regardless, back off offset by one }
  777.         END;
  778.  
  779.     SetHandleSize(fPadding, GetHandleSize(fOldText) + savedSize + fStylePad);
  780.     FailMemError;
  781.     whoCares := Munger(fOldText, 0, NIL, 0, @savedChar, savedSize);
  782.     FailMemError;
  783.     fOldStart := curStart;                                { Treat this as though original selection }
  784.     fNewStart := curStart;                                { …had included this character }
  785.     fNewEnd := curStart;
  786.     fTextPad := fTextPad - savedSize;
  787.     END;
  788.  
  789. {--------------------------------------------------------------------------------------------------}
  790. {$S TERes}
  791.  
  792. PROCEDURE TTETypingCommand.BkSpcRight(theText: Handle;
  793.                                       curStart: INTEGER);
  794.  
  795.     VAR
  796.         savedSize:            INTEGER;
  797.  
  798.     BEGIN
  799.     savedSize := 1;
  800.     IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
  801.         WHILE CharByte(theText^, curStart - savedSize) > 0 DO
  802.             savedSize := SUCC(savedSize);
  803.     SetHandleSize(fPadding, MAX( - (fTextPad - savedSize + fStylePad), 0));
  804.     FailMemError;
  805.     fNewEnd := fNewEnd - savedSize;
  806.     fTextPad := fTextPad - savedSize;
  807.  
  808.     SetHandleSize(fNewText, fNewEnd - fNewStart);        { Shouldn't fail as we're only shrinking it
  809.                                                          }
  810.     FailMemError;
  811.     END;
  812.  
  813. {--------------------------------------------------------------------------------------------------}
  814. { Forward delete courtesy of: Larry Goldman.  Used by permission. }
  815. {$S TERes}
  816.  
  817. PROCEDURE TTETypingCommand.FwdDelete(theText: Handle;
  818.                                      curStart, curEnd: INTEGER);
  819.  
  820.     TYPE
  821.         TSPtr                = ^TextStyle;
  822.  
  823.     VAR
  824.         savedSize:            INTEGER;
  825.         theHeight:            INTEGER;
  826.         theAscent:            INTEGER;
  827.         oldSize:            LONGINT;
  828.         whoCares:            LONGINT;
  829.         aTextStyle:         TSPtr;
  830.         savedChar:            PACKED ARRAY [0..3] OF Char;
  831.         delStyle:            TextStyle;
  832.         textSize:            LONGINT;
  833.         oldTextSize:        LONGINT;
  834.  
  835.     BEGIN
  836.     textSize := GetHandleSize(theText);
  837.     IF (curStart = curEnd) & (curStart < textSize) THEN
  838.         BEGIN
  839.  
  840.         savedSize := 0;                                 {Get the complete character}
  841.         IF qNeedsScriptManager | gConfiguration.hasScriptManager THEN
  842.             WHILE (curStart + savedSize <= textSize) & (CharByte(theText^, curStart + savedSize) >
  843.                   0) DO
  844.                 savedSize := SUCC(savedSize);
  845.         savedSize := savedSize + 1;
  846.         {$IFC qDebug}
  847.         IF savedSize > 4 THEN
  848.             ProgramBreak('Character > 4 bytes');
  849.         {$ENDC}
  850.  
  851.         IF savedSize = 1 THEN                            { Slight speed optimization for normal case
  852.                                                          }
  853.         {$Push} {$R-}
  854.             savedChar[0] := CharsHandle(theText)^^[curStart]
  855.             {$Pop}
  856.         ELSE
  857.             BlockMove(Ptr(ORD(theText^) + curStart), @savedChar, savedSize);
  858.  
  859.         IF (curStart >= fNewStart) & (curStart < fNewEnd) THEN { char is within fNewText }
  860.             BEGIN                                        {Remove the char from fNewText and update
  861.                                                          fNewEnd and fTextPad}
  862.             SetHandleSize(fPadding, MAX( - (fTextPad - savedSize + fStylePad), 0));
  863.             FailMemError;
  864.             fNewEnd := fNewEnd - savedSize;
  865.             fTextPad := fTextPad - savedSize;
  866.  
  867.             { Shouldn't fail as we're only shrinking it }
  868.             whoCares := Munger(fNewText, curStart - fNewStart, NIL, savedSize, @savedChar, 0);
  869.             FailMemError;
  870.             END
  871.         ELSE                                            { add char to the end of fOldChars, don't
  872.                                                          update fOldEnd, but update fPadding}
  873.             BEGIN
  874.             oldTextSize := GetHandleSize(fOldText);
  875.             IF fTEView.fStyleType = kWithStyle THEN     { Only do this if styles are around }
  876.                 BEGIN
  877.                 TEGetStyle(curStart, delStyle,            { Get the style of the deleted character }
  878.                            theHeight, theAscent, fHTE); { (1 or 4 bytes, it's all only one style) }
  879.  
  880.                 IF NOT EqualBlocks(@delStyle,            { If style doesn't match last in the list }
  881.                                    @fOldStyles^^.scrpStyleTab[fOldStyles^^.scrpNStyles -
  882.                                    1].scrpFont, SIZEOF(TextStyle)) THEN
  883.                     BEGIN                                { …then insert new style at end of list }
  884.                     fTEView.fSpecsChanged := TRUE;        { User backspaced into new style! }
  885.  
  886.                     oldSize :=                            { Make room for the new style element }
  887.                       GetHandleSize(Handle(fOldStyles));
  888.                     SetHandleSize(Handle(fOldStyles), oldSize + SIZEOF(ScrpSTElement));
  889.                     FailMemError;
  890.                     fStylePad := fStylePad + SIZEOF(ScrpSTElement);
  891.  
  892.                     fOldStyles^^.scrpNStyles :=         { One more style }
  893.                       SUCC(fOldStyles^^.scrpNStyles);
  894.                     WITH fOldStyles^^.scrpStyleTab[fOldStyles^^.scrpNStyles - 1] DO
  895.                         BEGIN
  896.                         scrpStartChar := oldTextSize;
  897.                         scrpHeight := theHeight;        { Fill in the blanks }
  898.                         scrpAscent := theAscent;
  899.                         aTextStyle := TSPtr(@scrpFont);
  900.                         aTextStyle^ := delStyle;
  901.                         END;
  902.                     END;
  903.                 END;
  904.  
  905.             SetHandleSize(fPadding, oldTextSize + savedSize + fStylePad);
  906.             FailMemError;
  907.             whoCares := Munger(fOldText, oldTextSize, NIL, 0, @savedChar, savedSize);
  908.             FailMemError;
  909.             fTextPad := fTextPad - savedSize;
  910.  
  911.             END;
  912.         END;
  913.     END;
  914.  
  915. {--------------------------------------------------------------------------------------------------}
  916. { ??? All this handle munging is expensive.  Better would be to accumulate memory in
  917.   "chunks" of, say, 16 bytes so that this checking need not happen every time through.
  918.   Fortunately, the normal cases are not that bad. }
  919. {$S TERes}
  920.  
  921. PROCEDURE TTETypingCommand.AddCharacter(aChar: Char);
  922.  
  923.     VAR
  924.         theText:            Handle;
  925.         curSelStart:        INTEGER;
  926.         curSelEnd:            INTEGER;
  927.         savedPerm:            BOOLEAN;
  928.         fi:                 FailInfo;
  929.         index:                INTEGER;
  930.  
  931.     PROCEDURE HdlCharFailed(error: OSErr;
  932.                             message: LONGINT);
  933.  
  934.         BEGIN
  935.         savedPerm := PermAllocation(savedPerm);
  936.         END;
  937.  
  938.     BEGIN
  939.     fView.Update;                                        { Makes sure that all of TE's actions are
  940.                                                          Visible }
  941.     IF fView.Focus THEN;
  942.     WITH fHTE^^ DO                                        { Get handy info about the text handle }
  943.         BEGIN
  944.         curSelStart := selStart;
  945.         curSelEnd := selEnd;
  946.         theText := hText;
  947.         END;
  948.     CatchFailures(fi, HdlCharFailed);
  949.     savedPerm := PermAllocation(TRUE);
  950.  
  951.  { Update the fNewText handle and other information.  Note that because of backspace,
  952.   this can be tricky.}
  953.  
  954.     IF (aChar = chFwdDelete) THEN
  955.         FwdDelete(theText, curSelStart, curSelEnd)        { User types forward delete, so keep in
  956.                                                          synch}
  957.  
  958.     ELSE IF aChar <> chBackspace THEN                    { Not a backspace. Do the right thing }
  959.         DoNormalChar(aChar)
  960.  
  961.     ELSE IF (curSelStart <= fOldStart) &                { User typed backspace so keep in synch }
  962.             (curSelStart > 0) & (curSelStart = curSelEnd) THEN
  963.         BkSpcLeft(theText, curSelStart)                 { Handle backspace to left of start }
  964.  
  965.     ELSE IF fNewEnd > fNewStart THEN                    { Delete 1 character from end of fNewText }
  966.         BkSpcRight(theText, curSelStart);                { Handle backspace to right of start }
  967.  
  968.     savedPerm := PermAllocation(savedPerm);
  969.     Success(fi);
  970.  
  971.     IF aChar <> chFwdDelete THEN
  972.  { Let TextEdit have the character, as either 1) we're adding a byte, so we know there
  973.   is a reserve tank, so the worst this will do is eat into it a little, or 2) we're
  974.   deleting a character, which can only decrease memory usage. }
  975.         TEKey(aChar, fHTE)
  976.     ELSE IF (curSelStart <> curSelEnd) THEN             { forward delete with chars selected}
  977.         TEDelete(fHTE)
  978.     ELSE IF (curSelStart < GetHandleSize(theText)) THEN
  979.         BEGIN                                            { forward delete with insertion point}
  980.         TEKey(chRight, fHTE);
  981.         TEKey(chBackspace, fHTE);
  982.         END;
  983.  
  984.     fTEView.SynchView(kRedraw);                         { Now clean up the view. }
  985.  
  986.     {$IFC qDebug}
  987.     IF pTEIntenseDebugging THEN
  988.         BEGIN
  989.         WrLblHandleContents('fOldText', fOldText);
  990.         WRITELN;
  991.         WrLblHandleContents('fNewText', fNewText);
  992.         WRITELN;
  993.         DumpTTECommand(SELF);
  994.         END;
  995.     {$ENDC}
  996.  
  997.     END;
  998.  
  999. {--------------------------------------------------------------------------------------------------}
  1000. {$S TERes}
  1001.  
  1002. PROCEDURE TTETypingCommand.DoIt; OVERRIDE;
  1003.  
  1004.     BEGIN
  1005.     AddCharacter(fFirstChar);
  1006.     {$IFC qDebug}
  1007.     IF pTEIntenseDebugging THEN
  1008.         DumpTTECommand(SELF);
  1009.     {$ENDC}
  1010.     END;
  1011.  
  1012. {--------------------------------------------------------------------------------------------------}
  1013.  
  1014. {$S TEDoCommand}
  1015.  
  1016. PROCEDURE TTETypingCommand.RedoIt; OVERRIDE;
  1017.  
  1018.     VAR
  1019.         currentStyle:        TextStyle;
  1020.         lineHeight:         INTEGER;
  1021.         fontAscent:         INTEGER;
  1022.         resetStyle:         BOOLEAN;
  1023.  
  1024.     BEGIN
  1025.     IF (fOldEnd - fOldStart) = GetHandleSize(fOldText) THEN
  1026.         BEGIN                                            { No chars were vacuumed}
  1027.         resetStyle := FALSE;
  1028.         IF (fTEView.fStyleType = kWithStyle) & (fOldEnd = fOldStart) THEN
  1029.             BEGIN
  1030.             TEGetStyle(fOldStart, currentStyle, lineHeight, fontAscent, fHTE);
  1031.             resetStyle := NOT EqualBlocks(@currentStyle, @fOldStyles^^.scrpStyleTab[0].scrpFont,
  1032.                                           SIZEOF(TextStyle));
  1033.             END;
  1034.  
  1035.         IF resetStyle THEN                                { The new text has a style of its own }
  1036.             fNewStyles := fOldStyles;                    { Make InstallNewText insert styles, too }
  1037.         INHERITED RedoIt;
  1038.         IF resetStyle THEN
  1039.             fNewStyles := NIL;                            { So fNewStyles doesn't get disposed }
  1040.         END
  1041.     ELSE
  1042.         BEGIN
  1043.         IF fTEView.Focus THEN;                            {??? What if Focus fails}
  1044.         TESetSelect(fOldStart, fOldStart + GetHandleSize(fOldText), fHTE); { select vacuumed chars,
  1045.             too }
  1046.         TEDelete(fHTE);                                 { Remove old text, including vacuumed chars}
  1047.         SetHandleSize(fPadding, MAX( - (fTextPad + fStylePad), 0));
  1048.         FailMemError;
  1049.         InstallNewText;
  1050.         fTEView.SynchView(kRedraw);
  1051.         {$IFC qDebug}
  1052.         IF pTEIntenseDebugging THEN
  1053.             DumpTTECommand(SELF);
  1054.         {$ENDC}
  1055.         END;
  1056.     END;
  1057.  
  1058. {--------------------------------------------------------------------------------------------------}
  1059. {$S TEDoCommand}
  1060.  
  1061. PROCEDURE TTETypingCommand.UndoIt; OVERRIDE;
  1062.  
  1063.     BEGIN
  1064.     CompleteTyping;
  1065.     INHERITED UndoIt;
  1066.     END;
  1067.  
  1068. {--------------------------------------------------------------------------------------------------}
  1069. {$S TERes}
  1070.  
  1071. PROCEDURE TTETypingCommand.CompleteTyping;
  1072.  
  1073.     VAR
  1074.         i:                    INTEGER;
  1075.         offset:             LONGINT;
  1076.  
  1077.     BEGIN
  1078.     fCompleted := TRUE;
  1079.  
  1080.     IF fTEView.fStyleType = kWithStyle THEN
  1081.         WITH fOldStyles^^ DO
  1082.             BEGIN
  1083.             offset := - scrpStyleTab[0].scrpStartChar;
  1084.             IF offset > 0 THEN
  1085.                 FOR i := 0 TO scrpNStyles - 1 DO
  1086.                     scrpStyleTab[i].scrpStartChar := scrpStyleTab[i].scrpStartChar + offset;
  1087.             END;
  1088.     {$IFC qDebug}
  1089.     IF pTEIntenseDebugging THEN
  1090.         DumpTTECommand(SELF);
  1091.     {$ENDC}
  1092.     END;
  1093.  
  1094. {--------------------------------------------------------------------------------------------------}
  1095. {$S TEFields}
  1096.  
  1097. PROCEDURE TTETypingCommand.Fields(PROCEDURE DoToField(fieldName: Str255;
  1098.                                                       fieldAddr: Ptr;
  1099.                                                       fieldType: INTEGER)); OVERRIDE;
  1100.  
  1101.     BEGIN
  1102.     DoToField('TTETypingCommand', NIL, bClass);
  1103.     DoToField('fCompleted', @fCompleted, bBoolean);
  1104.     DoToField('fFirstChar', @fFirstChar, bBoolean);
  1105.     INHERITED Fields(DoToField);
  1106.     END;
  1107.